<?php
namespace Core\Datastorage;

use Core as Core;

/**
* Mapping class definition. This class manage the mapping between database and entities. This mapping is build from .hbm.xml files found on the project.
*
* @author Didelot Guillaume
* @version 1.0.0
* @copyright Copyright (c) 2015, Didelot Guillaume
*
* @method Mapping Singleton()
* @method array ParseMappingFiles()
* @method Mapping Create($filePath)
*
* @todo Save the mapping array in a session variable 
*/
class Mapping {
	
	/**
	* @property string $Type The property type
	*/
	public $Type;
	
	/**
	* @property string $Table The targeted table
	*/
	public $Table;
	
	/**
	* @property string $PrimaryColumn The primary column
	*/
	public $PrimaryColumn;
	
	/**
	* @property array $Properties All properties of the application
	*/
	public $Properties;

	/**
	*	@property string $AliasTable This is the alias computed from the table
	*/
	public $AliasTable;
	
	/**
	* @property Mapping $instance The session instance
	*/
	private static $instance;

	/**
	* Default constructor
	*/
	private function __construct() 
	{
		$this->CreationDate = date("Y-m-d H:i:s");
	}

	/**
	* The singleton method
	*/
	public static function Singleton() 
	{
		if (!isset(self::$instance)) {
			$c = __CLASS__;
			self::$instance = new $c;
		}
	
		return self::$instance;
	}
	
	/**
	* Parse all mapping files
	*
	* @return array All mapping files found on the project
	*/
	public function getMappingFiles()
	{
		$result = null;
		
		Core\CoreCommons\Logger::Info("ParseMappingFiles - Start");
		$mappings = array();
		$filesPath = array();
		
		$rootPath = DATASTORAGE_DIR . "/Mappings/";
		
		Core\CoreCommons\Logger::Info("ParseMappingFiles - Find all hbm files in $rootPath");
		
		if(!file_exists($rootPath))
		{
			throw new Exception("The mappings directory doesn't exist.");
		}
		
		$files = scandir($rootPath);
		
		foreach($files as &$file)
		{
			if (strpos($file, '.hbm.xml') !== false)
			{
				$filesPath[] = $rootPath . $file;
			}
		}
		
		//For each mapping file create a mapping object
		foreach($filesPath as &$file)
		{
			Core\CoreCommons\Logger::Debug("Parsing file : " . $file);
			
			$mappingobject = $this->Create($file);
			
			//Set the mapping object on the dictionary
			if(isset($mappingobject))
			{
				if(isset($mappings[$mappingobject->Type]))
				{
					throw new \Exception(sprintf("Mapping %s already exist.", $mappingobject->Type));
				}
				
				$mappings[$mappingobject->Type] = $mappingobject;
			}
			
			//Compute alias
			$index = 0;
			foreach($mappings as $mapping)
			{
				//[Class type, type occurate]
				$complexTypes = array();
				$complexIndex = array();
				$defaultAlias = sprintf('ent_%s', $index);
				
				$mapping->AliasTable = $defaultAlias;
				$complexAliasCounter = 1;
				
				//Set the default alias on all properties
				foreach($mapping->Properties as $property)
				{
					$property->Alias = $defaultAlias;
					if($property->IsComplex == true)
					{
						$property->Alias .= $complexAliasCounter;
						$complexAliasCounter++;
					}
				}
				$index++;
			}	
		}
		
		$result = $mappings;
		
		return $result;
	}
	
	/**
	* Build a mapping from a file
	*
	* @param string $filePath the mapping file path 
	*
	* @return Mapping A mapping object created from xml file
	*/
	private function Create($filePath)
	{
		$mappingobject = new Core\Datastorage\Mapping();
		$mappingobject->Properties = array();
		
		$xml = new \DomDocument();
		$xml->load($filePath);

		$nodelist = $xml->getElementsByTagName("mapping");
		foreach($nodelist as $node)
		{
			if ($node->hasAttribute("table")) {
				$mappingobject->Table = $node->getAttribute("table");
			}
			if ($node->hasAttribute("class")) {
				$mappingobject->Type = $node->getAttribute("class");
			}
			if ($node->hasAttribute("primarycolumn")) {
				$mappingobject->PrimaryColumn = $node->getAttribute("primarycolumn");
			}
		}
		
		$propertynodelist = $xml->getElementsByTagName('property');
		foreach($propertynodelist as $propertyLine)
		{  
			$name = null;
			$column = null;
			$type = null;
			if ($propertyLine->hasAttribute("Name")) {
				$name = $propertyLine->getAttribute("Name");
			}
			if ($propertyLine->hasAttribute("Column")) {
				$column = $propertyLine->getAttribute("Column");
			}
			if ($propertyLine->hasAttribute("Type")) {
				$type = $propertyLine->getAttribute("Type");
			}
			
			$property = new Core\Datastorage\Property($name, $column, $type);
			
			$mappingobject->Properties[(string)$name] = $property;
		}
		
		$propertynodelist = $xml->getElementsByTagName('many-to-one');
		foreach($propertynodelist as $propertyLine)
		{  
			$name = null;
			$column = null;
			$type = null;
			if ($propertyLine->hasAttribute("Name")) {
				$name = $propertyLine->getAttribute("Name");
			}
			if ($propertyLine->hasAttribute("Column")) {
				$column = $propertyLine->getAttribute("Column");
			}
			if ($propertyLine->hasAttribute("Type")) {
				$type = $propertyLine->getAttribute("Type");
			}
			
			$property = new Core\Datastorage\Property($name, $column, $type, true);
			
			$mappingobject->Properties[(string)$name] = $property;
		}

		return $mappingobject;
	}
}
?> 